﻿using System;
using System.Collections.Generic;
using System.Windows;
using System.Windows.Media;
using System.Windows.Media.Media3D;
using System.Windows.Controls;
using System.Windows.Shapes;
using System.Windows.Controls.Primitives;
using Bling.WPF;
using Bling.DSL;
using Bling.Geom;
using Bling.Util;
using Bling.Properties;
using Bling.D3D;

namespace Bling.Lighting {

  public enum Light { POINTLIGHT, DIRECTIONALLIGHT, SPOTLIGHT, ENVIRMENTCUBE};
  public enum MapInfo { 
    COLOR = 0x1, 
    DIFFUSE = 0x2,
    NORMAL = 0x4, 
    HEIGHT = 0x8, 
    HEIGHT_CALNOR = 0x10, 
  };
 
  public class MaterialMapInfo : DependencyObject {

    private static readonly GetProperty<MaterialMapInfo, MapInfo> MapInfoProperty =
      "MapInfo".NewProperty<MaterialMapInfo, MapInfo>(Bling.Lighting.MapInfo.COLOR);

    private static readonly GetProperty<MaterialMapInfo, Color> ColorProperty =
      "Color".NewProperty<MaterialMapInfo, Color>(Colors.Black);
    private static readonly GetProperty<MaterialMapInfo, Brush> DiffuseMapProperty =
      "DiffuseMap".NewProperty<MaterialMapInfo, Brush>(Brushes.Black);
    private static readonly GetProperty<MaterialMapInfo, Brush> NormalMapProperty =
      "NormalMap".NewProperty<MaterialMapInfo, Brush>(Brushes.Black);
    private static readonly GetProperty<MaterialMapInfo, Brush> HeightMapProperty =
      "HeightMap".NewProperty<MaterialMapInfo, Brush>(Brushes.Black);
    private static readonly GetProperty<MaterialMapInfo, double> HeightScaleProperty =
      "HeightScale".NewProperty<MaterialMapInfo, double>(1.0);
    private static readonly GetProperty<MaterialMapInfo, Point> MapSizeProperty =
      "MapSize".NewProperty<MaterialMapInfo, Point>(new Point(0, 0));
    private static readonly GetProperty<MaterialMapInfo, Point> MapLeftTopProperty =
      "MapLeftTop".NewProperty<MaterialMapInfo, Point>(new Point(0, 0));

    public MapInfo MapInfo { get; set; }
    /*
    public EnumBl<MapInfo> MapInfo {
      get { return MapInfoProperty[this]; }
      set { MapInfo.Bind = value; }
    }*/

    public ColorBl Color {
      get { return ColorProperty[this]; }
      set { Color.Bind = value; }
    }
    public BrushBl DiffuseMap{
      get { return DiffuseMapProperty[this]; }
      set { DiffuseMap.Bind = value; }

    }

    public BrushBl NormalMap {
      get { return NormalMapProperty[this]; }
      set { NormalMap.Bind = value; }
    }

    public BrushBl HeightMap {
      get { return HeightMapProperty[this]; }
      set { HeightMap.Bind = value; }
    }

    public DoubleBl HeightScale {
      get { return HeightScaleProperty[this]; }
      set { HeightScale.Bind = value; }
    }

    public PointBl MapSize {
      get { return MapSizeProperty[this]; }
      set { MapSize.Bind = value; }
    }

    public PointBl MapLeftTop {
      get { return MapLeftTopProperty[this]; }
      set { MapLeftTop.Bind = value; }
    }
  };

  public static class LightingTechniques {

    /// <summary>
    /// transform the color value in normamap(rgb:0~1) to the value of a normal in the 3d space(xyz:-1~1)
    /// </summary>
    /// <param name="tex"></param>
    /// <returns></returns>
    private static Point3DBl getNormal(Point3DBl tex){
      return tex * 2 - new Point3DBl(1, 1, 1);
    }

    private static Point3DBl getNormal(BrushBl tex, PointBl uv, PointBl size, DoubleBl Scale){
      var dx = tex[new PointBl(uv.X + 1d / size.X, uv.Y)].ScR - tex[new PointBl(uv.X - 1d / size.X, uv.Y)].ScR;
      var dy = tex[new PointBl(uv.X, uv.Y + 1d / size.Y)].ScR - tex[new PointBl(uv.X, uv.Y - 1d / size.Y)].ScR;
      return new Point3DBl(-dx * Scale, -dy * Scale, 1).Normal;
    }
    
    /// <summary>
    /// calculate the attenuation
    /// </summary>
    /// <param name="LightSource.Attenuation"></param>
    /// <param name="dis"></param>
    /// <returns></returns>
    private static DoubleBl Attenuation(PointLightBl.AttenuationSet attenuationCoefficient, DoubleBl dis) {
      return 1d / (attenuationCoefficient.Quadratic * dis * dis + attenuationCoefficient.Linear * dis + attenuationCoefficient.Constant);
    }
    private static DoubleBl Attenuation(SpotLightBl.AttenuationSet attenuationCoefficient, DoubleBl dis) {
      return 1d / (attenuationCoefficient.Quadratic * dis * dis + attenuationCoefficient.Linear * dis + attenuationCoefficient.Constant);
    }

    private static Point3DBl getDiffuseColor(Point3DBl position, Point3DBl normal, PointLightBl LightSource) {
      var dir = LightSource.Position - position;
      var dis = dir.Length;
      dir = dir.Normal;
      var dot0 = dir.Dot(normal);
      return LightSource.Color.ScRGB * dot0.Max(0) * Attenuation(LightSource.Attenuation, dis);
    }

    private static Point3DBl getDiffuseColor(Point3DBl position, Point3DBl normal, SpotLightBl LightSource) {
      var dir = LightSource.Position - position;
      var dis = dir.Length;
      dir = dir.Normal;
      var dot0 = dir.Dot(normal);
      var dot1 = -LightSource.Direction.Dot(dir);
      var innerCos = LightSource.InnerConeAngle.Cos;
      var outerCos = LightSource.OuterConeAngle.Cos;
      var att = Attenuation(LightSource.Attenuation, dis) * dot1;
      var spot = (dot1 > innerCos).Condition(att, (dot1 > outerCos).Condition( att * (dot1 - outerCos) / (innerCos - outerCos), 0.0));
      return LightSource.Color.ScRGB * dot0.Max(0) * spot;
    }

    private static Point3DBl getDiffuseColor(Point3DBl normal, DirectionalLightBl LightSource) {
      var dir = LightSource.Direction.Normal;
      var dot0 = dir.Dot(normal);
      return LightSource.Color.ScRGB * dot0.Max(0);
    }

    private static Point3DBl getSpecularColor(Point3DBl position, Point3DBl normal, PointLightBl LightSource, Point3DBl eyePosition, DoubleBl n, DoubleBl k) {
      var dir = (LightSource.Position - position).Normal;
      var dot = dir.Dot(normal);
      var r = -dir + 2 * dot * normal;
      var viewDir = (eyePosition - position).Normal;

      return (dot > 0).Condition(LightSource.Color.ScRGB * (r.Dot(viewDir)).Max(0).Pow(n) * k, new Point3DBl(0, 0, 0));
    }

    private static Point3DBl getSpecularColor(Point3DBl position, Point3DBl normal, SpotLightBl LightSource, Point3DBl eyePosition, DoubleBl n, DoubleBl k) {
      var dir = (LightSource.Position - position).Normal;
      var dot0 = dir.Dot(normal);
      var r = -dir + 2 * dot0 * normal;

      var viewDir = (eyePosition - position).Normal;

      var dot1 = -LightSource.Direction.Dot(dir);
      var innerCos = LightSource.InnerConeAngle.Cos;
      var outerCos = LightSource.OuterConeAngle.Cos;
      var spot = (dot1 > innerCos).Condition(dot1, (dot1 > outerCos).Condition(dot1 * (dot1 - outerCos) / (innerCos - outerCos), 0.0));

      return (dot0 > 0).Condition(LightSource.Color.ScRGB * r.Dot(viewDir).Pow(n) * k * spot, new Point3DBl(0, 0, 0));
    }

    private static Point3DBl getSpecularColor(Point3DBl position, Point3DBl normal, DirectionalLightBl LightSource, Point3DBl eyePosition, DoubleBl n, DoubleBl k) {
      var dir = LightSource.Direction.Normal;
      var dot = dir.Dot(normal);
      var r = -dir + 2 * dot * normal;
      var viewDir = (eyePosition - position).Normal;

      return (dot > 0).Condition(LightSource.Color.ScRGB * r.Dot(viewDir).Pow(n) * k, new Point3DBl(0, 0, 0));
    }

    private static Point3DBl getDiffuseSpecularColor(Point3DBl position, Point3DBl normal, PointLightBl LightSource, Point3DBl eyePosition, DoubleBl n, DoubleBl k) {
      var dir = LightSource.Position - position;
      var dis = dir.Length;
      dir = dir.Normal;
      var dot0 = dir.Dot(normal);

      var r = -dir + 2 * dot0 * normal;
      var viewDir = (eyePosition - position).Normal;

      return (dot0 > 0).Condition(LightSource.Color.ScRGB * (r.Dot(viewDir)).Max(0).Pow(n) * k, new Point3DBl(0, 0, 0)) + LightSource.Color.ScRGB * dot0.Max(0) * Attenuation(LightSource.Attenuation, dis);
    }

    private static Point3DBl getDiffuseSpecularColor(Point3DBl position, Point3DBl normal, SpotLightBl LightSource, Point3DBl eyePosition, DoubleBl n, DoubleBl k) {
      var dir = LightSource.Position - position;
      var dis = dir.Length;
      dir = dir.Normal;
      var dot0 = dir.Dot(normal);
      var dot1 = -LightSource.Direction.Dot(dir);
      var innerCos = LightSource.InnerConeAngle.Cos;
      var outerCos = LightSource.OuterConeAngle.Cos;

      var r = -dir + 2 * dot0 * normal;

      var viewDir = (eyePosition - position).Normal;

      var spot = (dot1 > innerCos).Condition(dot1, (dot1 > outerCos).Condition(dot1 * (dot1 - outerCos) / (innerCos - outerCos), 0.0));

      return (dot0 > 0).Condition(LightSource.Color.ScRGB * r.Dot(viewDir).Pow(n) * k * spot, new Point3DBl(0, 0, 0)) + LightSource.Color.ScRGB * dot0.Max(0) * spot * Attenuation(LightSource.Attenuation, dis);
    }

    private static Point3DBl getDiffuseSpecularColor(Point3DBl position, Point3DBl normal, DirectionalLightBl LightSource, Point3DBl eyePosition, DoubleBl n, DoubleBl k) {
      var dir = LightSource.Direction.Normal;
      var dot = dir.Dot(normal);
      var r = -dir + 2 * dot * normal;
      var viewDir = (eyePosition - position).Normal;

      return (dot > 0).Condition(LightSource.Color.ScRGB * r.Dot(viewDir).Pow(n) * k, new Point3DBl(0, 0, 0)) + LightSource.Color.ScRGB * dot.Max(0);
    }
    /*******************************
    public static ColorBl DiffuseColor(PointBl uv, MaterialMapInfo matInfo, DirectionalLightBl LightSource) {

      var color = ((matInfo.MapInfo & MapInfo.DIFFUSE) == MapInfo.DIFFUSE).Condition(matInfo.DiffuseMap[uv],
                  ((matInfo.MapInfo & MapInfo.COLOR) == MapInfo.COLOR).Condition(matInfo.Color, Colors.Gray));
      var normal = ((matInfo.MapInfo & MapInfo.NORMAL) == MapInfo.NORMAL).Condition(getNormal(matInfo.NormalMap[uv].ScRGB),
                  ((matInfo.MapInfo & MapInfo.HEIGHT_CALNOR) == MapInfo.HEIGHT_CALNOR).Condition(getNormal(matInfo.HeightMap, uv, matInfo.MapSize, matInfo.HeightScale), new Point3DBl(0, 0, 1)));

      var dir = LightSource.Direction.Normal;
      var dot = dir.Dot(normal);

      return ColorBl.FromScRGB(1.0, (color.ScRGB * LightSource.Color.ScRGB * dot));
    }

    public static ColorBl DiffuseColor(PointBl uv, MaterialMapInfo matInfo, PointLightBl LightSource) {

      var height = ((matInfo.MapInfo & MapInfo.HEIGHT) == MapInfo.HEIGHT | (matInfo.MapInfo & MapInfo.HEIGHT_CALNOR) == MapInfo.HEIGHT_CALNOR).Condition(matInfo.HeightMap[uv].ScR * matInfo.HeightScale, 0.0);
      var color = ((matInfo.MapInfo & MapInfo.DIFFUSE) == MapInfo.DIFFUSE).Condition(matInfo.DiffuseMap[uv],
                  ((matInfo.MapInfo & MapInfo.COLOR) == MapInfo.COLOR).Condition(matInfo.Color, Colors.Gray));
      var normal = ((matInfo.MapInfo & MapInfo.NORMAL) == MapInfo.NORMAL).Condition(getNormal(matInfo.NormalMap[uv].ScRGB),
                  ((matInfo.MapInfo & MapInfo.HEIGHT_CALNOR) == MapInfo.HEIGHT_CALNOR).Condition(getNormal(matInfo.HeightMap, uv, matInfo.MapSize, matInfo.HeightScale), new Point3DBl(0, 0, 1)));

      var lightPosition = LightSource.Position.XY - matInfo.MapLeftTop;
      var dir = new Point3DBl(lightPosition - uv * matInfo.MapSize, LightSource.Position.Z - height);
      var dis = dir.Length;
      dir = dir.Normal;
      var dot = dir.Dot(normal);

      return ColorBl.FromScRGB(1.0, (color.ScRGB * LightSource.Color.ScRGB * dot * Attenuation(LightSource.Attenuation, dis)));
    }
    ***********************************/

/////-----------diffuseColor

//----------------------color
    /// <summary>
    /// simple lighting of paper, only diffuse color is included
    /// </summary>
    /// <param name="uv">coordinate of point</param>
    /// <param name="DiffuseColor">color of paper</param>
    /// <param name="LightSource">information of the light source</param>
    /// <param name="LeftTop">LeftTop of the object to draw</param>
    /// <param name="Size">size of the object to draw</param>
    /// <param name="attenuationQuotient">
    /// attenuation quotient of the diffuse color, 
    /// described as a quadratic equation like "1.0/(X * d^2 + Y * d + Z), 
    /// where d is the distance between the lightSource and the point"
    /// </param>
    /// <returns>the final color after lighting calculation</returns>
    public static ColorBl DiffuseColor(PointBl uv, ColorBl DiffuseColor, PointLightBl LightSource, PointBl LeftTop, PointBl Size) {
      var pos = LeftTop + uv * Size;
      var diffuseLight = getDiffuseColor(pos, new Point3DBl(0, 0, 1), LightSource);
      return ColorBl.FromScRGB(1.0, (DiffuseColor.ScRGB * diffuseLight));
    }

    public static ColorBl DiffuseColor(PointBl uv, ColorBl DiffuseColor, SpotLightBl LightSource, PointBl LeftTop, PointBl Size) {
      var pos = LeftTop + uv * Size;
      var diffuseLight = getDiffuseColor(pos, new Point3DBl(0, 0, 1), LightSource);
      return ColorBl.FromScRGB(1.0, (DiffuseColor.ScRGB * diffuseLight));
    }
    
    /// <summary>
    /// simple lighting of paper, only diffuse color is included
    /// </summary>
    /// <param name="uv">coordinate of point</param>
    /// <param name="DiffuseColor">color of paper</param>
    /// <param name="LightSource">information of the light source</param>
    /// <returns>the final color after lighting calculation</returns>
    public static ColorBl DiffuseColor(PointBl uv, ColorBl DiffuseColor, DirectionalLightBl LightSource) {
      var diffuseLight = getDiffuseColor(new Point3DBl(0, 0, 1), LightSource);
      return ColorBl.FromScRGB(1.0, (DiffuseColor.ScRGB * diffuseLight));
    }

//-----------------diffuseMap
    /// <summary>
    /// simple lighting of paper, only diffuse color is included
    /// </summary>
    /// <param name="uv">coordinate of point</param>
    /// <param name="DiffuseColor">color of paper</param>
    /// <param name="LightSource">information of the light source</param>
    /// <param name="LeftTop">LeftTop of the object to draw</param>
    /// <param name="Size">size of the object to draw</param>
    /// <param name="attenuationQuotient">
    /// attenuation quotient of the diffuse color, 
    /// described as a quadratic equation like "1.0/(X * d^2 + Y * d + Z), 
    /// where d is the distance between the lightSource and the point"
    /// </param>
    /// <returns>the final color after lighting calculation</returns>
    public static ColorBl DiffuseColor(PointBl uv, BrushBl DiffuseColor, PointLightBl LightSource, PointBl LeftTop, PointBl Size) {
      var pos = LeftTop + uv * Size;
      var diffuseLight = getDiffuseColor(pos, new Point3DBl(0, 0, 1), LightSource);
      return ColorBl.FromScRGB(1.0, (DiffuseColor[uv].ScRGB * diffuseLight));
    }

    public static ColorBl DiffuseColor(PointBl uv, BrushBl DiffuseColor, SpotLightBl LightSource, PointBl LeftTop, PointBl Size) {
      var pos = LeftTop + uv * Size;
      var diffuseLight = getDiffuseColor(pos, new Point3DBl(0, 0, 1), LightSource);
      return ColorBl.FromScRGB(1.0, (DiffuseColor[uv].ScRGB * diffuseLight));
    }
    
    /// <summary>
    /// simple lighting of paper, only diffuse color is included
    /// </summary>
    /// <param name="uv">coordinate of point</param>
    /// <param name="DiffuseColor">color of paper</param>
    /// <param name="LightSource">information of the light source</param>
    /// <returns>the final color after lighting calculation</returns>
    public static ColorBl DiffuseColor(PointBl uv, BrushBl DiffuseColor, DirectionalLightBl LightSource) {
      var diffuseLight = getDiffuseColor(new Point3DBl(0, 0, 1), LightSource);
      return ColorBl.FromScRGB(1.0, (DiffuseColor[uv].ScRGB * diffuseLight));
    }

//--------------color,normalMap
    /// <summary>
    /// lighting effect only with diffuse color, adding normal mapping
    /// </summary>
    /// <param name="uv">coordinate of point</param>
    /// <param name="DiffuseColor">diffuse color of the material</param>
    /// <param name="NormalMap">the normal map to describe the normal direction of every point</param>
    /// <param name="LightSource">information of the light source</param>
    /// <param name="LeftTop">LeftTop of the object to draw</param>
    /// <param name="Size">size of the object to draw</param>
    /// <param name="attenuationQuotient">
    /// attenuation quotient of the diffuse color, 
    /// described as a quadratic equation like "X * d^2 + Y * d + Z, 
    /// where d is the distance between the lightSource and the point"
    /// </param>
    /// <returns>the final color after lighting calculation</returns>
    public static ColorBl DiffuseColor(PointBl uv, ColorBl DiffuseColor, BrushBl NormalMap, PointLightBl LightSource, PointBl LeftTop, PointBl Size) {
      var pos = LeftTop + uv * Size;
      var normal = getNormal(NormalMap[uv].ScRGB);
      var diffuseLight = getDiffuseColor(pos, normal, LightSource);
      return ColorBl.FromScRGB(1.0, (DiffuseColor.ScRGB * diffuseLight));
    }

    public static ColorBl DiffuseColor(PointBl uv, ColorBl DiffuseColor, BrushBl NormalMap, SpotLightBl LightSource, PointBl LeftTop, PointBl Size) {
      var pos = LeftTop + uv * Size;
      var normal = getNormal(NormalMap[uv].ScRGB);
      var diffuseLight = getDiffuseColor(pos, normal, LightSource);
      return ColorBl.FromScRGB(1.0, (DiffuseColor.ScRGB * diffuseLight));
    }
    /// <summary>
    /// lighting effect only with diffuse color, adding normal mapping
    /// </summary>
    /// <param name="uv">coordinate of point</param>
    /// <param name="DiffuseColor">diffuse color of the material</param>
    /// <param name="NormalMap">the normal map to describe the normal direction of every point</param>
    /// <param name="LightSource">information of the light source</param>
    /// <param name="LeftTop">LeftTop of the object to draw</param>
    /// <param name="Size">size of the object to draw</param>
    /// <param name="attenuationQuotient">
    /// attenuation quotient of the diffuse color, 
    /// described as a quadratic equation like "X * d^2 + Y * d + Z, 
    /// where d is the distance between the lightSource and the point"
    /// </param>
    /// <returns>the final color after lighting calculation</returns>
    public static ColorBl DiffuseColor(PointBl uv, ColorBl DiffuseColor, BrushBl NormalMap, DirectionalLightBl LightSource) {
      var normal = getNormal(NormalMap[uv].ScRGB);
      var diffuseLight = getDiffuseColor(normal, LightSource);
      return ColorBl.FromScRGB(1.0, (DiffuseColor.ScRGB * diffuseLight));
    }

//---------------diffuseMap,normalMap
    /// <summary>
    /// lighting effect only with diffuse color, adding normal mapping
    /// </summary>
    /// <param name="uv">coordinate of point</param>
    /// <param name="DiffuseColor">diffuse color of the material, could be an image</param>
    /// <param name="NormalMap">the normal map to describe the normal direction of every point</param>
    /// <param name="LightSource">information of the light source</param>
    /// <param name="LeftTop">LeftTop of the object to draw</param>
    /// <param name="Size">size of the object to draw</param>
    /// <param name="attenuationQuotient">
    /// attenuation quotient of the diffuse color, 
    /// described as a quadratic equation like "X * d^2 + Y * d + Z, 
    /// where d is the distance between the lightSource and the point"
    /// </param>
    /// <returns>the final color after lighting calculation</returns>
    public static ColorBl DiffuseColor(PointBl uv, BrushBl DiffuseColor, BrushBl NormalMap, PointLightBl LightSource, PointBl LeftTop, PointBl Size) {
      var pos = LeftTop + uv * Size;
      var normal = getNormal(NormalMap[uv].ScRGB);
      var diffuseLight = getDiffuseColor(pos, normal, LightSource);

      return ColorBl.FromScRGB(1.0, (DiffuseColor[uv].ScRGB * diffuseLight));
    }

    public static ColorBl DiffuseColor(PointBl uv, BrushBl DiffuseColor, BrushBl NormalMap, SpotLightBl LightSource, PointBl LeftTop, PointBl Size) {
      var pos = LeftTop + uv * Size;
      var normal = getNormal(NormalMap[uv].ScRGB);
      var diffuseLight = getDiffuseColor(pos, normal, LightSource);

      return ColorBl.FromScRGB(1.0, (DiffuseColor[uv].ScRGB * diffuseLight));
    }
    /// <summary>
    /// lighting effect only with diffuse color, adding normal mapping
    /// </summary>
    /// <param name="uv">coordinate of point</param>
    /// <param name="DiffuseColor">diffuse color of the material, could be an image</param>
    /// <param name="NormalMap">the normal map to describe the normal direction of every point</param>
    /// <param name="LightSource">information of the light source</param>
    /// <param name="LeftTop">LeftTop of the object to draw</param>
    /// <param name="Size">size of the object to draw</param>
    /// <param name="attenuationQuotient">
    /// attenuation quotient of the diffuse color, 
    /// described as a quadratic equation like "X * d^2 + Y * d + Z, 
    /// where d is the distance between the lightSource and the point"
    /// </param>
    /// <returns>the final color after lighting calculation</returns>
    public static ColorBl DiffuseColor(PointBl uv, BrushBl DiffuseColor, BrushBl NormalMap, DirectionalLightBl LightSource) {
      var normal = getNormal(NormalMap[uv].ScRGB);
      var diffuseLight = getDiffuseColor(normal, LightSource);
      return ColorBl.FromScRGB(1.0, (DiffuseColor[uv].ScRGB * diffuseLight));
    }

//-----------------color, heightMap
    /// <summary>
    /// lighting effect only with diffuse color, adding bump mapping (both normal and height)
    /// </summary>
    /// <param name="uv">coordinate of point</param>
    /// <param name="DiffuseColor">diffuse color of the material, could be an image</param>
    /// <param name="NormalMap">the normal map to describe the normal direction of every point</param>
    /// <param name="HeightMap">the height map to describe the height of every point</param>
    /// <param name="HeightScale">the height saved in HeightMap must be between 0 and 1, use this parameter to scale the height as you want</param>
    /// <param name="LightSource">information of the light source</param>
    /// <param name="LeftTop">LeftTop of the object to draw</param>
    /// <param name="Size">size of the object to draw</param>
    /// <param name="attenuationQuotient">
    /// attenuation quotient of the diffuse color, 
    /// described as a quadratic equation like "X * d^2 + Y * d + Z, 
    /// where d is the distance between the lightSource and the point"
    /// </param>
    /// <returns>the final color after lighting calculation</returns>
    public static ColorBl DiffuseColor(PointBl uv, ColorBl DiffuseColor, BrushBl HeightMap, DoubleBl HeightScale, PointLightBl LightSource, PointBl LeftTop, PointBl Size) {
      var pos = new Point3DBl(LeftTop + uv * Size, HeightMap[uv].ScR * HeightScale);
      var normal = getNormal(HeightMap, uv, Size, HeightScale);
      var diffuseLight = getDiffuseColor(pos, normal, LightSource);

      return ColorBl.FromScRGB(1.0, (DiffuseColor.ScRGB * diffuseLight));
    }

    public static ColorBl DiffuseColor(PointBl uv, ColorBl DiffuseColor, BrushBl HeightMap, DoubleBl HeightScale, SpotLightBl LightSource, PointBl LeftTop, PointBl Size) {
      var pos = new Point3DBl(LeftTop + uv * Size, HeightMap[uv].ScR * HeightScale);
      var normal = getNormal(HeightMap, uv, Size, HeightScale);
      var diffuseLight = getDiffuseColor(pos, normal, LightSource);

      return ColorBl.FromScRGB(1.0, (DiffuseColor.ScRGB * diffuseLight));
    } 
    /// <summary>
    /// lighting effect only with diffuse color, adding bump mapping (both normal and height)
    /// </summary>
    /// <param name="uv">coordinate of point</param>
    /// <param name="DiffuseColor">diffuse color of the material, could be an image</param>
    /// <param name="NormalMap">the normal map to describe the normal direction of every point</param>
    /// <param name="HeightMap">the height map to describe the height of every point</param>
    /// <param name="HeightScale">the height saved in HeightMap must be between 0 and 1, use this parameter to scale the height as you want</param>
    /// <param name="LightSource">information of the light source</param>
    /// <param name="LeftTop">LeftTop of the object to draw</param>
    /// <param name="Size">size of the object to draw</param>
    /// <param name="attenuationQuotient">
    /// attenuation quotient of the diffuse color, 
    /// described as a quadratic equation like "X * d^2 + Y * d + Z, 
    /// where d is the distance between the lightSource and the point"
    /// </param>
    /// <returns>the final color after lighting calculation</returns>
    public static ColorBl DiffuseColor(PointBl uv, ColorBl DiffuseColor, BrushBl HeightMap, DoubleBl HeightScale, DirectionalLightBl LightSource, PointBl Size) {
      var normal = getNormal(HeightMap, uv, Size, HeightScale);
      var diffuseLight = getDiffuseColor(normal, LightSource);
      return ColorBl.FromScRGB(1.0, (DiffuseColor.ScRGB * diffuseLight));
    } 

//-----------------diffuseMap, heightMap
    /// <summary>
    /// lighting effect only with diffuse color, adding bump mapping (both normal and height)
    /// </summary>
    /// <param name="uv">coordinate of point</param>
    /// <param name="DiffuseColor">diffuse color of the material, could be an image</param>
    /// <param name="NormalMap">the normal map to describe the normal direction of every point</param>
    /// <param name="HeightMap">the height map to describe the height of every point</param>
    /// <param name="HeightScale">the height saved in HeightMap must be between 0 and 1, use this parameter to scale the height as you want</param>
    /// <param name="LightSource">information of the light source</param>
    /// <param name="LeftTop">LeftTop of the object to draw</param>
    /// <param name="Size">size of the object to draw</param>
    /// <param name="attenuationQuotient">
    /// attenuation quotient of the diffuse color, 
    /// described as a quadratic equation like "X * d^2 + Y * d + Z, 
    /// where d is the distance between the lightSource and the point"
    /// </param>
    /// <returns>the final color after lighting calculation</returns>
    public static ColorBl DiffuseColor(PointBl uv, BrushBl DiffuseColor, BrushBl HeightMap, DoubleBl HeightScale, PointLightBl LightSource, PointBl LeftTop, PointBl Size) {
      var pos = new Point3DBl(LeftTop + uv * Size, HeightMap[uv].ScR * HeightScale);
      var normal = getNormal(HeightMap, uv, Size, HeightScale);
      var diffuseLight = getDiffuseColor(pos, normal, LightSource);

      return ColorBl.FromScRGB(1.0, (DiffuseColor[uv].ScRGB * diffuseLight));
    } 

    public static ColorBl DiffuseColor(PointBl uv, BrushBl DiffuseColor, BrushBl HeightMap, DoubleBl HeightScale, SpotLightBl LightSource, PointBl LeftTop, PointBl Size) {
      var pos = new Point3DBl(LeftTop + uv * Size, HeightMap[uv].ScR * HeightScale);
      var normal = getNormal(HeightMap, uv, Size, HeightScale);
      var diffuseLight = getDiffuseColor(pos, normal, LightSource);

      return ColorBl.FromScRGB(1.0, (DiffuseColor[uv].ScRGB * diffuseLight));
    } 
    /// <summary>
    /// lighting effect only with diffuse color, adding bump mapping (both normal and height)
    /// </summary>
    /// <param name="uv">coordinate of point</param>
    /// <param name="DiffuseColor">diffuse color of the material, could be an image</param>
    /// <param name="NormalMap">the normal map to describe the normal direction of every point</param>
    /// <param name="HeightMap">the height map to describe the height of every point</param>
    /// <param name="HeightScale">the height saved in HeightMap must be between 0 and 1, use this parameter to scale the height as you want</param>
    /// <param name="LightSource">information of the light source</param>
    /// <param name="LeftTop">LeftTop of the object to draw</param>
    /// <param name="Size">size of the object to draw</param>
    /// <param name="attenuationQuotient">
    /// attenuation quotient of the diffuse color, 
    /// described as a quadratic equation like "X * d^2 + Y * d + Z, 
    /// where d is the distance between the lightSource and the point"
    /// </param>
    /// <returns>the final color after lighting calculation</returns>
    public static ColorBl DiffuseColor(PointBl uv, BrushBl DiffuseColor, BrushBl HeightMap, DoubleBl HeightScale, DirectionalLightBl LightSource, PointBl Size) {
      var normal = getNormal(HeightMap, uv, Size, HeightScale);
      var diffuseLight = getDiffuseColor(normal, LightSource);
      return ColorBl.FromScRGB(1.0, (DiffuseColor[uv].ScRGB * diffuseLight));
    } 

/////----------------specular Color,so we don't need the diffuse color of object，in fact, the specular color of material is needed, we just set it as white
    
//--------no map
    /// <summary>
    /// lighting effect only with specular color
    /// </summary>
    /// <param name="uv">coordinate of point</param>
    /// <param name="LightSource">information of the light source</param>
    /// <param name="EyePos">position of eye/viewport</param>
    /// <param name="LeftTop">LeftTop of the object to draw</param>
    /// <param name="Size">size of the object to draw</param>
    /// <param name="n">
    /// the reflective index,usually from 1 to 2000, 
    /// the higher this number is, the surface looks more smoother, 
    /// that means the highlight spot smaller and brighter</param>
    /// <param name="k">specularity factor, usually between 0 and 1, can control the whole strength of the specular color</param>
    /// <returns>the final color after lighting calculation</returns>
    public static ColorBl SpecularColor(PointBl uv, PointLightBl LightSource, Point3DBl EyePos, PointBl LeftTop, PointBl Size, DoubleBl n, DoubleBl k) {
      var pos = LeftTop + uv * Size;
      var normal = new Point3DBl(0, 0, 1);
      var specularLight = getSpecularColor(pos, normal, LightSource, EyePos, n, k);

      return ColorBl.FromScRGB(1.0, specularLight);
    }

    public static ColorBl SpecularColor(PointBl uv, SpotLightBl LightSource, Point3DBl EyePos, PointBl LeftTop, PointBl Size, DoubleBl n, DoubleBl k) {
      var pos = LeftTop + uv * Size;
      var normal = new Point3DBl(0, 0, 1);
      var specularLight = getSpecularColor(pos, normal, LightSource, EyePos, n, k);

      return ColorBl.FromScRGB(1.0, specularLight);
    }    
    
    /// <summary>
    /// lighting effect only with specular color
    /// </summary>
    /// <param name="uv">coordinate of point</param>
    /// <param name="LightSource">information of the light source</param>
    /// <param name="EyePos">position of eye/viewport</param>
    /// <param name="LeftTop">LeftTop of the object to draw</param>
    /// <param name="Size">size of the object to draw</param>
    /// <param name="n">
    /// the reflective index,usually from 1 to 2000, 
    /// the higher this number is, the surface looks more smoother, 
    /// that means the highlight spot smaller and brighter</param>
    /// <param name="k">specularity factor, usually between 0 and 1, can control the whole strength of the specular color</param>
    /// <returns>the final color after lighting calculation</returns>
    public static ColorBl SpecularColor(PointBl uv, DirectionalLightBl LightSource, Point3DBl EyePos, PointBl LeftTop, PointBl Size, DoubleBl n, DoubleBl k) {
      var pos = LeftTop + uv * Size;
      var normal = new Point3DBl(0, 0, 1);
      var specularLight = getSpecularColor(pos, normal, LightSource, EyePos, n, k);
      return ColorBl.FromScRGB(1.0, specularLight);
    }

//--------normalmap
    /// <summary>
    /// lighting effect only with specular color
    /// </summary>
    /// <param name="uv">coordinate of point</param>
    /// <param name="NormalMap">the normal map to describe the normal direction of every point</param>
    /// <param name="LightSource">information of the light source</param>
    /// <param name="EyePos">position of eye/viewport</param>
    /// <param name="LeftTop">LeftTop of the object to draw</param>
    /// <param name="Size">size of the object to draw</param>
    /// <param name="n">
    /// the reflective index,usually from 1 to 2000, 
    /// the higher this number is, the surface looks more smoother, 
    /// that means the highlight spot smaller and brighter</param>
    /// <param name="k">specularity factor, usually between 0 and 1, can control the whole strength of the specular color</param>
    /// <returns>the final color after lighting calculation</returns>
     public static ColorBl SpecularColor(PointBl uv, BrushBl NormalMap, PointLightBl LightSource, Point3DBl EyePos, PointBl LeftTop, PointBl Size, DoubleBl n, DoubleBl k) {
      var pos = LeftTop + uv * Size;
      var normal = getNormal(NormalMap[uv].ScRGB);
      var specularLight = getSpecularColor(pos, normal, LightSource, EyePos, n, k);

      return ColorBl.FromScRGB(1.0, specularLight);
    }

     public static ColorBl SpecularColor(PointBl uv, BrushBl NormalMap, SpotLightBl LightSource, Point3DBl EyePos, PointBl LeftTop, PointBl Size, DoubleBl n, DoubleBl k) {
      var pos = LeftTop + uv * Size;
      var normal = getNormal(NormalMap[uv].ScRGB);
      var specularLight = getSpecularColor(pos, normal, LightSource, EyePos, n, k);

      return ColorBl.FromScRGB(1.0, specularLight);
    }    
    
    /// <summary>
    /// lighting effect only with specular color
    /// </summary>
    /// <param name="uv">coordinate of point</param>
    /// <param name="NormalMap">the normal map to describe the normal direction of every point</param>
    /// <param name="LightSource">information of the light source</param>
    /// <param name="EyePos">position of eye/viewport</param>
    /// <param name="LeftTop">LeftTop of the object to draw</param>
    /// <param name="Size">size of the object to draw</param>
    /// <param name="n">
    /// the reflective index,usually from 1 to 2000, 
    /// the higher this number is, the surface looks more smoother, 
    /// that means the highlight spot smaller and brighter</param>
    /// <param name="k">specularity factor, usually between 0 and 1, can control the whole strength of the specular color</param>
    /// <returns>the final color after lighting calculation</returns>
     public static ColorBl SpecularColor(PointBl uv, BrushBl NormalMap, DirectionalLightBl LightSource, Point3DBl EyePos, PointBl LeftTop, PointBl Size, DoubleBl n, DoubleBl k) {
      var pos = LeftTop + uv * Size;
      var normal = getNormal(NormalMap[uv].ScRGB);
      var specularLight = getSpecularColor(pos, normal, LightSource, EyePos, n, k);

      return ColorBl.FromScRGB(1.0, specularLight);
     }

//-------heightmap
     /// <summary>
     /// lighting effect only with specular color
     /// </summary>
     /// <param name="uv">coordinate of point</param>
     /// <param name="NormalMap">the normal map to describe the normal direction of every point</param>
     /// <param name="HeightMap">the height map to describe the height of every point</param>
     /// <param name="HeightScale">the height saved in HeightMap must be between 0 and 1, use this parameter to scale the height as you want</param>
     /// <param name="LightSource">information of the light source</param>
     /// <param name="EyePos">position of eye/viewport</param>
     /// <param name="LeftTop">LeftTop of the object to draw</param>
     /// <param name="Size">size of the object to draw</param>
     /// <param name="n">
     /// the reflective index,usually from 1 to 2000, 
     /// the higher this number is, the surface looks more smoother, 
     /// that means the highlight spot smaller and brighter</param>
     /// <param name="k">specularity factor, usually between 0 and 1, can control the whole strength of the specular color</param>
     /// <returns>the final color after lighting calculation</returns>
    public static ColorBl SpecularColor(PointBl uv, BrushBl HeightMap, DoubleBl HeightScale, PointLightBl LightSource, Point3DBl EyePos, PointBl LeftTop, PointBl Size, DoubleBl n, DoubleBl k) {
       var pos = new Point3DBl(LeftTop + uv * Size, HeightMap[uv].ScR * HeightScale);
       var normal = getNormal(HeightMap, uv, Size, HeightScale);
       var specularLight = getSpecularColor(pos, normal, LightSource, EyePos, n, k);

       return ColorBl.FromScRGB(1.0, specularLight);
     }

    public static ColorBl SpecularColor(PointBl uv, BrushBl HeightMap, DoubleBl HeightScale, SpotLightBl LightSource, Point3DBl EyePos, PointBl LeftTop, PointBl Size, DoubleBl n, DoubleBl k) {
       var pos = new Point3DBl(LeftTop + uv * Size, HeightMap[uv].ScR * HeightScale);
       var normal = getNormal(HeightMap, uv, Size, HeightScale);
       var specularLight = getSpecularColor(pos, normal, LightSource, EyePos, n, k);

       return ColorBl.FromScRGB(1.0, specularLight);
     } 
    
    /// <summary>
    /// lighting effect only with specular color
    /// </summary>
    /// <param name="uv">coordinate of point</param>
    /// <param name="NormalMap">the normal map to describe the normal direction of every point</param>
    /// <param name="HeightMap">the height map to describe the height of every point</param>
    /// <param name="HeightScale">the height saved in HeightMap must be between 0 and 1, use this parameter to scale the height as you want</param>
    /// <param name="LightSource">information of the light source</param>
    /// <param name="EyePos">position of eye/viewport</param>
    /// <param name="LeftTop">LeftTop of the object to draw</param>
    /// <param name="Size">size of the object to draw</param>
    /// <param name="n">
    /// the reflective index,usually from 1 to 2000, 
    /// the higher this number is, the surface looks more smoother, 
    /// that means the highlight spot smaller and brighter</param>
    /// <param name="k">specularity factor, usually between 0 and 1, can control the whole strength of the specular color</param>
    /// <returns>the final color after lighting calculation</returns>
    public static ColorBl SpecularColor(PointBl uv, BrushBl HeightMap, DoubleBl HeightScale, DirectionalLightBl LightSource, Point3DBl EyePos, PointBl LeftTop, PointBl Size, DoubleBl n, DoubleBl k) {
      var pos = new Point3DBl(LeftTop + uv * Size, HeightMap[uv].ScR * HeightScale);
      var normal = getNormal(HeightMap, uv, Size, HeightScale);
      var specularLight = getSpecularColor(pos, normal, LightSource, EyePos, n, k);

      return ColorBl.FromScRGB(1.0, specularLight);
    }

//------------------------both diffuse and specular color
//------only color        
    /// <summary>
    /// lighting effect with both diffuse color and specular color
    /// </summary>
    /// <param name="uv">coordinate of point</param>
    /// <param name="BaseMap">the main diffuse color of the object itself</param>
    /// <param name="LightSource">information of the light source</param>
    /// <param name="EyePos">position of eye/viewport</param>
    /// <param name="LeftTop">LeftTop of the object to draw</param>
    /// <param name="Size">size of the object to draw</param>
    /// <param name="attenuationQuotient">
    /// attenuation quotient of the diffuse color, 
    /// described as a quadratic equation like "X * d^2 + Y * d + Z, 
    /// where d is the distance between the lightSource and the point"
    /// </param>
    /// <param name="n">
    /// the reflective index,usually from 1 to 2000, 
    /// the higher this number is, the surface looks more smoother, 
    /// that means the highlight spot smaller and brighter</param>
    /// <param name="k">specularity factor, usually between 0 and 1, can control the whole strength of the specular color</param>
    /// <returns>the final color after lighting calculation</returns>
    public static ColorBl DiffuseSpecularColor(PointBl uv, ColorBl BaseColor, PointLightBl LightSource, Point3DBl EyePos, PointBl LeftTop, PointBl Size, DoubleBl n, DoubleBl k) {
      var pos = LeftTop + uv * Size;
      var normal = new Point3DBl(0, 0, 1);
      var diffuseSpecularLight = getDiffuseSpecularColor(pos, normal, LightSource, EyePos, n, k);

      return ColorBl.FromScRGB(1.0, (BaseColor.ScRGB * diffuseSpecularLight));
    }

    public static ColorBl DiffuseSpecularColor(PointBl uv, ColorBl BaseColor, SpotLightBl LightSource, Point3DBl EyePos, PointBl LeftTop, PointBl Size, DoubleBl n, DoubleBl k) {
      var pos = LeftTop + uv * Size;
      var normal = new Point3DBl(0, 0, 1);
      var diffuseSpecularLight = getDiffuseSpecularColor(pos, normal, LightSource, EyePos, n, k);

      return ColorBl.FromScRGB(1.0, (BaseColor.ScRGB * diffuseSpecularLight));
    }

    /// <summary>
    /// lighting effect with both diffuse color and specular color
    /// </summary>
    /// <param name="uv">coordinate of point</param>
    /// <param name="BaseMap">the main diffuse color of the object itself</param>
    /// <param name="LightSource">information of the light source</param>
    /// <param name="EyePos">position of eye/viewport</param>
    /// <param name="LeftTop">LeftTop of the object to draw</param>
    /// <param name="Size">size of the object to draw</param>
    /// <param name="attenuationQuotient">
    /// attenuation quotient of the diffuse color, 
    /// described as a quadratic equation like "X * d^2 + Y * d + Z, 
    /// where d is the distance between the lightSource and the point"
    /// </param>
    /// <param name="n">
    /// the reflective index,usually from 1 to 2000, 
    /// the higher this number is, the surface looks more smoother, 
    /// that means the highlight spot smaller and brighter</param>
    /// <param name="k">specularity factor, usually between 0 and 1, can control the whole strength of the specular color</param>
    /// <returns>the final color after lighting calculation</returns>
    public static ColorBl DiffuseSpecularColor(PointBl uv, ColorBl BaseColor, DirectionalLightBl LightSource, Point3DBl EyePos, PointBl LeftTop, PointBl Size, DoubleBl n, DoubleBl k) {
      var pos = LeftTop + uv * Size;
      var normal = new Point3DBl(0, 0, 1);
      var diffuseSpecularLight = getDiffuseSpecularColor(pos, normal, LightSource, EyePos, n, k);

      return ColorBl.FromScRGB(1.0, (BaseColor.ScRGB * diffuseSpecularLight));
    }

//------only diffusemap        
    /// <summary>
    /// lighting effect with both diffuse color and specular color
    /// </summary>
    /// <param name="uv">coordinate of point</param>
    /// <param name="BaseMap">the main diffuse color of the object itself</param>
    /// <param name="LightSource">information of the light source</param>
    /// <param name="EyePos">position of eye/viewport</param>
    /// <param name="LeftTop">LeftTop of the object to draw</param>
    /// <param name="Size">size of the object to draw</param>
    /// <param name="attenuationQuotient">
    /// attenuation quotient of the diffuse color, 
    /// described as a quadratic equation like "X * d^2 + Y * d + Z, 
    /// where d is the distance between the lightSource and the point"
    /// </param>
    /// <param name="n">
    /// the reflective index,usually from 1 to 2000, 
    /// the higher this number is, the surface looks more smoother, 
    /// that means the highlight spot smaller and brighter</param>
    /// <param name="k">specularity factor, usually between 0 and 1, can control the whole strength of the specular color</param>
    /// <returns>the final color after lighting calculation</returns>
    public static ColorBl DiffuseSpecularColor(PointBl uv, BrushBl BaseMap, PointLightBl LightSource, Point3DBl EyePos, PointBl LeftTop, PointBl Size, DoubleBl n, DoubleBl k) {
      var pos = LeftTop + uv * Size;
      var normal = new Point3DBl(0, 0, 1);
      var diffuseSpecularLight = getDiffuseSpecularColor(pos, normal, LightSource, EyePos, n, k);

      return ColorBl.FromScRGB(1.0, (BaseMap[uv].ScRGB * diffuseSpecularLight));
    }

    public static ColorBl DiffuseSpecularColor(PointBl uv, BrushBl BaseMap, SpotLightBl LightSource, Point3DBl EyePos, PointBl LeftTop, PointBl Size, DoubleBl n, DoubleBl k) {
      var pos = LeftTop + uv * Size;
      var normal = new Point3DBl(0, 0, 1);
      var diffuseSpecularLight = getDiffuseSpecularColor(pos, normal, LightSource, EyePos, n, k);

      return ColorBl.FromScRGB(1.0, (BaseMap[uv].ScRGB * diffuseSpecularLight));
    }

    /// <summary>
    /// lighting effect with both diffuse color and specular color
    /// </summary>
    /// <param name="uv">coordinate of point</param>
    /// <param name="BaseMap">the main diffuse color of the object itself</param>
    /// <param name="LightSource">information of the light source</param>
    /// <param name="EyePos">position of eye/viewport</param>
    /// <param name="LeftTop">LeftTop of the object to draw</param>
    /// <param name="Size">size of the object to draw</param>
    /// <param name="attenuationQuotient">
    /// attenuation quotient of the diffuse color, 
    /// described as a quadratic equation like "X * d^2 + Y * d + Z, 
    /// where d is the distance between the lightSource and the point"
    /// </param>
    /// <param name="n">
    /// the reflective index,usually from 1 to 2000, 
    /// the higher this number is, the surface looks more smoother, 
    /// that means the highlight spot smaller and brighter</param>
    /// <param name="k">specularity factor, usually between 0 and 1, can control the whole strength of the specular color</param>
    /// <returns>the final color after lighting calculation</returns>
    public static ColorBl DiffuseSpecularColor(PointBl uv, BrushBl BaseMap, DirectionalLightBl LightSource, Point3DBl EyePos, PointBl LeftTop, PointBl Size, DoubleBl n, DoubleBl k) {
      var pos = LeftTop + uv * Size;
      var normal = new Point3DBl(0, 0, 1);
      var diffuseSpecularLight = getDiffuseSpecularColor(pos, normal, LightSource, EyePos, n, k);

      return ColorBl.FromScRGB(1.0, (BaseMap[uv].ScRGB * diffuseSpecularLight));
    }

//--------color, normalmap
    /// <summary>
    /// lighting effect with both diffuse color and specular color
    /// </summary>
    /// <param name="uv">coordinate of point</param>
    /// <param name="BaseColor">the main diffuse color of the object itself</param>
    /// <param name="LightSource">information of the light source</param>
    /// <param name="EyePos">position of eye/viewport</param>
    /// <param name="LeftTop">LeftTop of the object to draw</param>
    /// <param name="Size">size of the object to draw</param>
    /// <param name="attenuationQuotient">
    /// attenuation quotient of the diffuse color, 
    /// described as a quadratic equation like "X * d^2 + Y * d + Z, 
    /// where d is the distance between the lightSource and the point"
    /// </param>
    /// <param name="n">
    /// the reflective index,usually from 1 to 2000, 
    /// the higher this number is, the surface looks more smoother, 
    /// that means the highlight spot smaller and brighter</param>
    /// <param name="k">specularity factor, usually between 0 and 1, can control the whole strength of the specular color</param>
    /// <returns>the final color after lighting calculation</returns>
    public static ColorBl DiffuseSpecularColor(PointBl uv, ColorBl BaseColor, BrushBl NormalMap, PointLightBl LightSource, Point3DBl EyePos, PointBl LeftTop, PointBl Size, DoubleBl n, DoubleBl k) {
      var pos = LeftTop + uv * Size;
      var normal = getNormal(NormalMap[uv].ScRGB);
      var diffuseSpecularLight = getDiffuseSpecularColor(pos, normal, LightSource, EyePos, n, k);

      return ColorBl.FromScRGB(1.0, (BaseColor.ScRGB * diffuseSpecularLight));
    }

    public static ColorBl DiffuseSpecularColor(PointBl uv, ColorBl BaseColor, BrushBl NormalMap, SpotLightBl LightSource, Point3DBl EyePos, PointBl LeftTop, PointBl Size, DoubleBl n, DoubleBl k) {
      var pos = LeftTop + uv * Size;
      var normal = getNormal(NormalMap[uv].ScRGB);
      var diffuseSpecularLight = getDiffuseSpecularColor(pos, normal, LightSource, EyePos, n, k);

      return ColorBl.FromScRGB(1.0, (BaseColor.ScRGB * diffuseSpecularLight));
    }

    /// <summary>
    /// lighting effect with both diffuse color and specular color
    /// </summary>
    /// <param name="uv">coordinate of point</param>
    /// <param name="BaseColor">the main diffuse color of the object itself</param>
    /// <param name="LightSource">information of the light source</param>
    /// <param name="EyePos">position of eye/viewport</param>
    /// <param name="LeftTop">LeftTop of the object to draw</param>
    /// <param name="Size">size of the object to draw</param>
    /// <param name="attenuationQuotient">
    /// attenuation quotient of the diffuse color, 
    /// described as a quadratic equation like "X * d^2 + Y * d + Z, 
    /// where d is the distance between the lightSource and the point"
    /// </param>
    /// <param name="n">
    /// the reflective index,usually from 1 to 2000, 
    /// the higher this number is, the surface looks more smoother, 
    /// that means the highlight spot smaller and brighter</param>
    /// <param name="k">specularity factor, usually between 0 and 1, can control the whole strength of the specular color</param>
    /// <returns>the final color after lighting calculation</returns>
    public static ColorBl DiffuseSpecularColor(PointBl uv, ColorBl BaseColor, BrushBl NormalMap, DirectionalLightBl LightSource, Point3DBl EyePos, PointBl LeftTop, PointBl Size, DoubleBl n, DoubleBl k) {
      var pos = LeftTop + uv * Size;
      var normal = getNormal(NormalMap[uv].ScRGB);
      var diffuseSpecularLight = getDiffuseSpecularColor(pos, normal, LightSource, EyePos, n, k);

      return ColorBl.FromScRGB(1.0, (BaseColor.ScRGB * diffuseSpecularLight));
    }

//-------diffusemap, normalmap
    /// <summary>
    /// lighting effect with both diffuse color and specular color
    /// </summary>
    /// <param name="uv">coordinate of point</param>
    /// <param name="BaseMap">the main diffuse color of the object itself</param>
    /// <param name="LightSource">information of the light source</param>
    /// <param name="EyePos">position of eye/viewport</param>
    /// <param name="LeftTop">LeftTop of the object to draw</param>
    /// <param name="Size">size of the object to draw</param>
    /// <param name="attenuationQuotient">
    /// attenuation quotient of the diffuse color, 
    /// described as a quadratic equation like "X * d^2 + Y * d + Z, 
    /// where d is the distance between the lightSource and the point"
    /// </param>
    /// <param name="n">
    /// the reflective index,usually from 1 to 2000, 
    /// the higher this number is, the surface looks more smoother, 
    /// that means the highlight spot smaller and brighter</param>
    /// <param name="k">specularity factor, usually between 0 and 1, can control the entire strength of the specular color</param>
    /// <returns>the final color after lighting calculation</returns>
    public static ColorBl DiffuseSpecularColor(PointBl uv, BrushBl BaseMap, BrushBl NormalMap, PointLightBl LightSource, Point3DBl EyePos, PointBl LeftTop, PointBl Size, DoubleBl n, DoubleBl k) {
      var pos = LeftTop + uv * Size;
      var normal = getNormal(NormalMap[uv].ScRGB);
      var diffuseSpecularLight = getDiffuseSpecularColor(pos, normal, LightSource, EyePos, n, k);

      return ColorBl.FromScRGB(1.0, (BaseMap[uv].ScRGB * diffuseSpecularLight));
    }

    public static ColorBl DiffuseSpecularColor(PointBl uv, BrushBl BaseMap, BrushBl NormalMap, SpotLightBl LightSource, Point3DBl EyePos, PointBl LeftTop, PointBl Size, DoubleBl n, DoubleBl k) {
      var pos = LeftTop + uv * Size;
      var normal = getNormal(NormalMap[uv].ScRGB);
      var diffuseSpecularLight = getDiffuseSpecularColor(pos, normal, LightSource, EyePos, n, k);

      return ColorBl.FromScRGB(1.0, (BaseMap[uv].ScRGB * diffuseSpecularLight));
    }
    /// <summary>
    /// lighting effect with both diffuse color and specular color
    /// </summary>
    /// <param name="uv">coordinate of point</param>
    /// <param name="BaseMap">the main diffuse color of the object itself</param>
    /// <param name="LightSource">information of the light source</param>
    /// <param name="EyePos">position of eye/viewport</param>
    /// <param name="LeftTop">LeftTop of the object to draw</param>
    /// <param name="Size">size of the object to draw</param>
    /// <param name="attenuationQuotient">
    /// attenuation quotient of the diffuse color, 
    /// described as a quadratic equation like "X * d^2 + Y * d + Z, 
    /// where d is the distance between the lightSource and the point"
    /// </param>
    /// <param name="n">
    /// the reflective index,usually from 1 to 2000, 
    /// the higher this number is, the surface looks more smoother, 
    /// that means the highlight spot smaller and brighter</param>
    /// <param name="k">specularity factor, usually between 0 and 1, can control the entire strength of the specular color</param>
    /// <returns>the final color after lighting calculation</returns>
    public static ColorBl DiffuseSpecularColor(PointBl uv, BrushBl BaseMap, BrushBl NormalMap, DirectionalLightBl LightSource, Point3DBl EyePos, PointBl LeftTop, PointBl Size, DoubleBl n, DoubleBl k) {
      var pos = LeftTop + uv * Size;
      var normal = getNormal(NormalMap[uv].ScRGB);
      var diffuseSpecularLight = getDiffuseSpecularColor(pos, normal, LightSource, EyePos, n, k);

      return ColorBl.FromScRGB(1.0, (BaseMap[uv].ScRGB * diffuseSpecularLight));
    }
    
//------color, heightmap
    /// <summary>
    /// lighting effect with both diffuse color and specular color
    /// </summary>
    /// <param name="uv">coordinate of point</param>
    /// <param name="BaseMap">the main diffuse color of the object itself</param>
    /// <param name="NormalMap">the normal map to describe the normal direction of every point</param>
    /// <param name="HeightMap">the height map to describe the height of every point</param>
    /// <param name="HeightScale">the height saved in HeightMap must be between 0 and 1, use this parameter to scale the height as you want</param>
    /// <param name="LightSource">information of the light source</param>
    /// <param name="EyePos">position of eye/viewport</param>
    /// <param name="LeftTop">LeftTop of the object to draw</param>
    /// <param name="Size">size of the object to draw</param>
    /// <param name="attenuationQuotient">
    /// attenuation quotient of the diffuse color, 
    /// described as a quadratic equation like "X * d^2 + Y * d + Z, 
    /// where d is the distance between the lightSource and the point"
    /// </param>
    /// <param name="n">
    /// the reflective index,usually from 1 to 2000, 
    /// the higher this number is, the surface looks more smoother, 
    /// that means the highlight spot smaller and brighter</param>
    /// <param name="k">specularity factor, usually between 0 and 1, can control the whole strength of the specular color</param>
    /// <returns>the final color after lighting calculation</returns>
    public static ColorBl DiffuseSpecularColor(PointBl uv, ColorBl BaseColor, BrushBl HeightMap, DoubleBl HeightScale, PointLightBl LightSource, Point3DBl EyePos, PointBl LeftTop, PointBl Size, DoubleBl n, DoubleBl k) {
      var pos = new Point3DBl(LeftTop + uv * Size, HeightMap[uv].ScR * HeightScale);
      var normal = getNormal(HeightMap, uv, Size, HeightScale);
      var diffuseSpecularLight = getDiffuseSpecularColor(pos, normal, LightSource, EyePos, n, k);

      return ColorBl.FromScRGB(1.0, (BaseColor.ScRGB * diffuseSpecularLight));
    }

    public static ColorBl DiffuseSpecularColor(PointBl uv, ColorBl BaseColor, BrushBl HeightMap, DoubleBl HeightScale, SpotLightBl LightSource, Point3DBl EyePos, PointBl LeftTop, PointBl Size, DoubleBl n, DoubleBl k) {
      var pos = new Point3DBl(LeftTop + uv * Size, HeightMap[uv].ScR * HeightScale);
      var normal = getNormal(HeightMap, uv, Size, HeightScale);
      var diffuseSpecularLight = getDiffuseSpecularColor(pos, normal, LightSource, EyePos, n, k);

      return ColorBl.FromScRGB(1.0, (BaseColor.ScRGB * diffuseSpecularLight));
    }

    /// <summary>
    /// lighting effect with both diffuse color and specular color
    /// </summary>
    /// <param name="uv">coordinate of point</param>
    /// <param name="BaseMap">the main diffuse color of the object itself</param>
    /// <param name="NormalMap">the normal map to describe the normal direction of every point</param>
    /// <param name="HeightMap">the height map to describe the height of every point</param>
    /// <param name="HeightScale">the height saved in HeightMap must be between 0 and 1, use this parameter to scale the height as you want</param>
    /// <param name="LightSource">information of the light source</param>
    /// <param name="EyePos">position of eye/viewport</param>
    /// <param name="LeftTop">LeftTop of the object to draw</param>
    /// <param name="Size">size of the object to draw</param>
    /// <param name="attenuationQuotient">
    /// attenuation quotient of the diffuse color, 
    /// described as a quadratic equation like "X * d^2 + Y * d + Z, 
    /// where d is the distance between the lightSource and the point"
    /// </param>
    /// <param name="n">
    /// the reflective index,usually from 1 to 2000, 
    /// the higher this number is, the surface looks more smoother, 
    /// that means the highlight spot smaller and brighter</param>
    /// <param name="k">specularity factor, usually between 0 and 1, can control the whole strength of the specular color</param>
    /// <returns>the final color after lighting calculation</returns>
    public static ColorBl DiffuseSpecularColor(PointBl uv, ColorBl BaseColor, BrushBl NormalMap, BrushBl HeightMap, DoubleBl HeightScale, DirectionalLightBl LightSource, Point3DBl EyePos, PointBl LeftTop, PointBl Size, DoubleBl n, DoubleBl k) {
      var pos = new Point3DBl(LeftTop + uv * Size, HeightMap[uv].ScR * HeightScale);
      var normal = getNormal(HeightMap, uv, Size, HeightScale);
      var diffuseSpecularLight = getDiffuseSpecularColor(pos, normal, LightSource, EyePos, n, k);

      return ColorBl.FromScRGB(1.0, (BaseColor.ScRGB * diffuseSpecularLight));
    }

//------diffusemap, heightmap
    /// <summary>
    /// lighting effect with both diffuse color and specular color
    /// </summary>
    /// <param name="uv">coordinate of point</param>
    /// <param name="BaseMap">the main diffuse color of the object itself</param>
    /// <param name="NormalMap">the normal map to describe the normal direction of every point</param>
    /// <param name="HeightMap">the height map to describe the height of every point</param>
    /// <param name="HeightScale">the height saved in HeightMap must be between 0 and 1, use this parameter to scale the height as you want</param>
    /// <param name="LightSource">information of the light source</param>
    /// <param name="EyePos">position of eye/viewport</param>
    /// <param name="LeftTop">LeftTop of the object to draw</param>
    /// <param name="Size">size of the object to draw</param>
    /// <param name="attenuationQuotient">
    /// attenuation quotient of the diffuse color, 
    /// described as a quadratic equation like "X * d^2 + Y * d + Z, 
    /// where d is the distance between the lightSource and the point"
    /// </param>
    /// <param name="n">
    /// the reflective index,usually from 1 to 2000, 
    /// the higher this number is, the surface looks more smoother, 
    /// that means the highlight spot smaller and brighter</param>
    /// <param name="k">specularity factor, usually between 0 and 1, can control the whole strength of the specular color</param>
    /// <returns>the final color after lighting calculation</returns>
    public static ColorBl DiffuseSpecularColor(PointBl uv, BrushBl BaseMap, BrushBl HeightMap, DoubleBl HeightScale, PointLightBl LightSource, Point3DBl EyePos, PointBl LeftTop, PointBl Size, DoubleBl n, DoubleBl k) {
      var pos = new Point3DBl(LeftTop + uv * Size, HeightMap[uv].ScR * HeightScale);
      var normal = getNormal(HeightMap, uv, Size, HeightScale);
      var diffuseSpecularLight = getDiffuseSpecularColor(pos, normal, LightSource, EyePos, n, k);

      return ColorBl.FromScRGB(1.0, (BaseMap[uv].ScRGB * diffuseSpecularLight));
    }

    public static ColorBl DiffuseSpecularColor(PointBl uv, BrushBl BaseMap, BrushBl HeightMap, DoubleBl HeightScale, SpotLightBl LightSource, Point3DBl EyePos, PointBl LeftTop, PointBl Size, DoubleBl n, DoubleBl k) {
      var pos = new Point3DBl(LeftTop + uv * Size, HeightMap[uv].ScR * HeightScale);
      var normal = getNormal(HeightMap, uv, Size, HeightScale);
      var diffuseSpecularLight = getDiffuseSpecularColor(pos, normal, LightSource, EyePos, n, k);

      return ColorBl.FromScRGB(1.0, (BaseMap[uv].ScRGB * diffuseSpecularLight));
    }

    /// <summary>
    /// lighting effect with both diffuse color and specular color
    /// </summary>
    /// <param name="uv">coordinate of point</param>
    /// <param name="BaseMap">the main diffuse color of the object itself</param>
    /// <param name="NormalMap">the normal map to describe the normal direction of every point</param>
    /// <param name="HeightMap">the height map to describe the height of every point</param>
    /// <param name="HeightScale">the height saved in HeightMap must be between 0 and 1, use this parameter to scale the height as you want</param>
    /// <param name="LightSource">information of the light source</param>
    /// <param name="EyePos">position of eye/viewport</param>
    /// <param name="LeftTop">LeftTop of the object to draw</param>
    /// <param name="Size">size of the object to draw</param>
    /// <param name="attenuationQuotient">
    /// attenuation quotient of the diffuse color, 
    /// described as a quadratic equation like "X * d^2 + Y * d + Z, 
    /// where d is the distance between the lightSource and the point"
    /// </param>
    /// <param name="n">
    /// the reflective index,usually from 1 to 2000, 
    /// the higher this number is, the surface looks more smoother, 
    /// that means the highlight spot smaller and brighter</param>
    /// <param name="k">specularity factor, usually between 0 and 1, can control the whole strength of the specular color</param>
    /// <returns>the final color after lighting calculation</returns>
    public static ColorBl DiffuseSpecularColor(PointBl uv, BrushBl BaseMap, BrushBl NormalMap, BrushBl HeightMap, DoubleBl HeightScale, DirectionalLightBl LightSource, Point3DBl EyePos, PointBl LeftTop, PointBl Size, DoubleBl n, DoubleBl k) {
      var pos = new Point3DBl(LeftTop + uv * Size, HeightMap[uv].ScR * HeightScale);
      var normal = getNormal(HeightMap, uv, Size, HeightScale);
      var diffuseSpecularLight = getDiffuseSpecularColor(pos, normal, LightSource, EyePos, n, k);

      return ColorBl.FromScRGB(1.0, (BaseMap[uv].ScRGB * diffuseSpecularLight));
    }

//---------------------glass color
    /// <summary>
    /// lighting effect of glass, with both refraction and reflection
    /// </summary>
    /// <param name="uv">coordinate of point</param>
    /// <param name="GlassColor">the color of the glass itself</param>
    /// <param name="BackgroundMap">the image showed behind the glass</param>
    /// <param name="NormalMap">the normal map to describe the normal direction of every point</param>
    /// <param name="HeightMap">the height map to describe the height of every point</param>
    /// <param name="HeightScale">the height saved in HeightMap must be between 0 and 1, use this parameter to scale the height as you want</param>
    /// <param name="LightSource">information of the light source</param>
    /// <param name="EyePos">position of eye/viewport</param>
    /// <param name="LeftTop">LeftTop of the object to draw</param>
    /// <param name="Size">size of the object to draw</param>
    /// <param name="n">
    /// the reflective index,usually from 1 to 2000, 
    /// the higher this number is, the surface looks more smoother, 
    /// that means the highlight spot smaller and brighter</param>
    /// <param name="k">specularity factor, usually between 0 and 1, can control the whole strength of the specular color</param>
    /// <param name="refractiveIndex">
    /// here means the relative refractive index(RI)
    /// the relative RI = RI of refracting medium /  RI of incident medium 
    /// usually we use the number 1.5, which equals to: RI of glass / RI of air
    /// </param>
    /// <param name="Thickness">the thickness of glass, usually between 1 and 100, the thicker the glass is, the effect of refraction is more obvious</param>
    /// <param name="LeftTop_Background">the lefttop of the background image</param>
    /// <param name="Size_Background">the size of the background image</param>
    /// <param name="Transparency">The transparency of the glass</param>
    /// <returns>the final color after lighting calculation</returns>
    public static ColorBl GlassColor(PointBl uv, ColorBl GlassColor, BrushBl BackgroundMap, BrushBl HeightMap, DoubleBl HeightScale, PointLightBl LightSource, Point3DBl EyePos, PointBl LeftTop, PointBl Size, DoubleBl n, DoubleBl k, DoubleBl refractiveIndex, DoubleBl Thickness, PointBl LeftTop_Background, PointBl Size_Background, DoubleBl Transparency) {
      var pos = new Point3DBl(LeftTop + uv * Size, HeightMap[uv].ScR * HeightScale);
      var normal = getNormal(HeightMap, uv, Size, HeightScale);
      var specularLight = getSpecularColor(pos, normal, LightSource, EyePos, n, k);

      var viewDir = (EyePos - pos).Normal;
      var cos1 = viewDir.Dot(normal);
      var cos2 = (1 - (1 - cos1.Square()) * refractiveIndex * refractiveIndex).Sqrt();
      var bias = (-refractiveIndex * viewDir - (cos2 - refractiveIndex * cos1) * normal) * (Thickness/100);

      var uv1 = (LeftTop - LeftTop_Background + uv * Size) / Size_Background;
      return ColorBl.FromScRGB(1.0, (GlassColor.ScRGB * specularLight)
                                    + BackgroundMap[uv1 + new PointBl(bias.X, bias.Y)].ScRGB * Transparency + GlassColor.ScRGB * (1.0 - Transparency));
    }

    public static ColorBl GlassColor(PointBl uv, ColorBl GlassColor, BrushBl BackgroundMap, BrushBl HeightMap, DoubleBl HeightScale, SpotLightBl LightSource, Point3DBl EyePos, PointBl LeftTop, PointBl Size, DoubleBl n, DoubleBl k, DoubleBl refractiveIndex, DoubleBl Thickness, PointBl LeftTop_Background, PointBl Size_Background, DoubleBl Transparency) {
      var pos = new Point3DBl(LeftTop + uv * Size, HeightMap[uv].ScR * HeightScale);
      var normal = getNormal(HeightMap, uv, Size, HeightScale);
      var specularLight = getSpecularColor(pos, normal, LightSource, EyePos, n, k);

      var viewDir = (EyePos - pos).Normal;
      var cos1 = viewDir.Dot(normal);
      var cos2 = (1 - (1 - cos1.Square()) * refractiveIndex * refractiveIndex).Sqrt();
      var bias = (-refractiveIndex * viewDir - (cos2 - refractiveIndex * cos1) * normal) * (Thickness/100);

      var uv1 = (LeftTop - LeftTop_Background + uv * Size) / Size_Background;
      return ColorBl.FromScRGB(1.0, (GlassColor.ScRGB * specularLight)
                                    + BackgroundMap[uv1 + new PointBl(bias.X, bias.Y)].ScRGB * Transparency + GlassColor.ScRGB * (1.0 - Transparency));
    } 
    
    /// <summary>
    /// lighting effect of glass, with both refraction and reflection
    /// </summary>
    /// <param name="uv">coordinate of point</param>
    /// <param name="GlassColor">the color of the glass itself</param>
    /// <param name="BackgroundMap">the image showed behind the glass</param>
    /// <param name="NormalMap">the normal map to describe the normal direction of every point</param>
    /// <param name="HeightMap">the height map to describe the height of every point</param>
    /// <param name="HeightScale">the height saved in HeightMap must be between 0 and 1, use this parameter to scale the height as you want</param>
    /// <param name="LightSource">information of the light source</param>
    /// <param name="EyePos">position of eye/viewport</param>
    /// <param name="LeftTop">LeftTop of the object to draw</param>
    /// <param name="Size">size of the object to draw</param>
    /// <param name="n">
    /// the reflective index,usually from 1 to 2000, 
    /// the higher this number is, the surface looks more smoother, 
    /// that means the highlight spot smaller and brighter</param>
    /// <param name="k">specularity factor, usually between 0 and 1, can control the whole strength of the specular color</param>
    /// <param name="refractiveIndex">
    /// here means the relative refractive index(RI)
    /// the relative RI = RI of refracting medium /  RI of incident medium 
    /// usually we use the number 1.5, which equals to: RI of glass / RI of air
    /// </param>
    /// <param name="Thickness">the thickness of glass, usually between 1 and 100, the thicker the glass is, the effect of refraction is more obvious</param>
    /// <param name="LeftTop_Background">the lefttop of the background image</param>
    /// <param name="Size_Background">the size of the background image</param>
    /// <param name="Transparency">The transparency of the glass</param>
    /// <returns>the final color after lighting calculation</returns>
    public static ColorBl GlassColor(PointBl uv, ColorBl GlassColor, BrushBl BackgroundMap, BrushBl HeightMap, DoubleBl HeightScale, DirectionalLightBl LightSource, Point3DBl EyePos, PointBl LeftTop, PointBl Size, DoubleBl n, DoubleBl k, DoubleBl refractiveIndex, DoubleBl Thickness, PointBl LeftTop_Background, PointBl Size_Background, DoubleBl Transparency) {
      var pos = new Point3DBl(LeftTop + uv * Size, HeightMap[uv].ScR * HeightScale);
      var normal = getNormal(HeightMap, uv, Size, HeightScale);
      var specularLight = getSpecularColor(pos, normal, LightSource, EyePos, n, k);

      var viewDir = (EyePos - pos).Normal;
      var cos1 = viewDir.Dot(normal);
      var cos2 = (1 - (1 - cos1.Square()) * refractiveIndex * refractiveIndex).Sqrt();
      var bias = (-refractiveIndex * viewDir - (cos2 - refractiveIndex * cos1) * normal) * (Thickness / 100);

      var uv1 = (LeftTop - LeftTop_Background + uv * Size) / Size_Background;
      return ColorBl.FromScRGB(1.0, (GlassColor.ScRGB * specularLight)
                                    + BackgroundMap[uv1 + new PointBl(bias.X, bias.Y)].ScRGB * Transparency + GlassColor.ScRGB * (1.0 - Transparency));
    }
    /// <summary>
    /// lighting effect of glass, with both refraction and reflection
    /// </summary>
    /// <param name="uv">coordinate of point</param>
    /// <param name="GlassColor">the color of the glass itself</param>
    /// <param name="BackgroundMap">the image showed behind the glass</param>
    /// <param name="NormalMap">the normal map to describe the normal direction of every point</param>
    /// <param name="LightSource">information of the light source</param>
    /// <param name="EyePos">position of eye/viewport</param>
    /// <param name="LeftTop">LeftTop of the object to draw</param>
    /// <param name="Size">size of the object to draw</param>
    /// <param name="n">
    /// the reflective index,usually from 1 to 2000, 
    /// the higher this number is, the surface looks more smoother, 
    /// that means the highlight spot smaller and brighter</param>
    /// <param name="k">specularity factor, usually between 0 and 1, can control the whole strength of the specular color</param>
    /// <param name="refractiveIndex">
    /// here means the relative refractive index(RI)
    /// the relative RI = RI of incident medium /  RI of refracting medium 
    /// usually we use the number 1.5, which equals to: RI of air / RI of glass
    /// </param>
    /// <param name="Thickness">the thickness of glass, usually between 1 and 100, the thicker the glass is, the effect of refraction is more obvious</param>
    /// <param name="LeftTop_Background">the lefttop of the background image</param>
    /// <param name="Size_Background">the size of the background image</param>
    /// <param name="Transparency">The transparency of the glass</param>
    /// <returns>the final color after lighting calculation</returns>
    public static ColorBl GlassColor(PointBl uv, ColorBl GlassColor, BrushBl BackgroundMap, BrushBl NormalMap, PointLightBl LightSource, Point3DBl EyePos, PointBl LeftTop, PointBl Size, DoubleBl n, DoubleBl k, DoubleBl refractiveIndex, DoubleBl Thickness, PointBl LeftTop_Background, PointBl Size_Background, DoubleBl Transparency) {
      var pos = LeftTop + uv * Size;
      var normal = getNormal(NormalMap[uv].ScRGB);
      var specularLight = getSpecularColor(pos, normal, LightSource, EyePos, n, k);

      var viewDir = (EyePos - pos).Normal;
      var cos1 = viewDir.Dot(normal);
      var cos2 = (1 - (1 - cos1.Square()) * refractiveIndex * refractiveIndex).Sqrt();
      var bias = (-refractiveIndex * viewDir - (cos2 - refractiveIndex * cos1) * normal) * (Thickness / 100);

      var uv1 = (LeftTop - LeftTop_Background + uv * Size) / Size_Background;
      return ColorBl.FromScRGB(1.0, (GlassColor.ScRGB * specularLight)
                                    + BackgroundMap[uv1 + new PointBl(bias.X, bias.Y)].ScRGB * Transparency + GlassColor.ScRGB * (1.0 - Transparency));
    }

    public static ColorBl GlassColor(PointBl uv, ColorBl GlassColor, BrushBl BackgroundMap, BrushBl NormalMap, SpotLightBl LightSource, Point3DBl EyePos, PointBl LeftTop, PointBl Size, DoubleBl n, DoubleBl k, DoubleBl refractiveIndex, DoubleBl Thickness, PointBl LeftTop_Background, PointBl Size_Background, DoubleBl Transparency) {
      var pos = LeftTop + uv * Size;
      var normal = getNormal(NormalMap[uv].ScRGB);
      var specularLight = getSpecularColor(pos, normal, LightSource, EyePos, n, k);

      var viewDir = (EyePos - pos).Normal;
      var cos1 = viewDir.Dot(normal);
      var cos2 = (1 - (1 - cos1.Square()) * refractiveIndex * refractiveIndex).Sqrt();
      var bias = (-refractiveIndex * viewDir - (cos2 - refractiveIndex * cos1) * normal) * (Thickness / 100);

      var uv1 = (LeftTop - LeftTop_Background + uv * Size) / Size_Background;
      return ColorBl.FromScRGB(1.0, (GlassColor.ScRGB * specularLight)
                                    + BackgroundMap[uv1 + new PointBl(bias.X, bias.Y)].ScRGB * Transparency + GlassColor.ScRGB * (1.0 - Transparency));
    }  
    
    /// <summary>
    /// lighting effect of glass, with both refraction and reflection
    /// </summary>
    /// <param name="uv">coordinate of point</param>
    /// <param name="GlassColor">the color of the glass itself</param>
    /// <param name="BackgroundMap">the image showed behind the glass</param>
    /// <param name="NormalMap">the normal map to describe the normal direction of every point</param>
    /// <param name="LightSource">information of the light source</param>
    /// <param name="EyePos">position of eye/viewport</param>
    /// <param name="LeftTop">LeftTop of the object to draw</param>
    /// <param name="Size">size of the object to draw</param>
    /// <param name="n">
    /// the reflective index,usually from 1 to 2000, 
    /// the higher this number is, the surface looks more smoother, 
    /// that means the highlight spot smaller and brighter</param>
    /// <param name="k">specularity factor, usually between 0 and 1, can control the whole strength of the specular color</param>
    /// <param name="refractiveIndex">
    /// here means the relative refractive index(RI)
    /// the relative RI = RI of incident medium /  RI of refracting medium 
    /// usually we use the number 1.5, which equals to: RI of air / RI of glass
    /// </param>
    /// <param name="Thickness">the thickness of glass, usually between 1 and 100, the thicker the glass is, the effect of refraction is more obvious</param>
    /// <param name="LeftTop_Background">the lefttop of the background image</param>
    /// <param name="Size_Background">the size of the background image</param>
    /// <param name="Transparency">The transparency of the glass</param>
    /// <returns>the final color after lighting calculation</returns>
    public static ColorBl GlassColor(PointBl uv, ColorBl GlassColor, BrushBl BackgroundMap, BrushBl NormalMap, DirectionalLightBl LightSource, Point3DBl EyePos, PointBl LeftTop, PointBl Size, DoubleBl n, DoubleBl k, DoubleBl refractiveIndex, DoubleBl Thickness, PointBl LeftTop_Background, PointBl Size_Background, DoubleBl Transparency) {
      var pos = LeftTop + uv * Size;
      var normal = getNormal(NormalMap[uv].ScRGB);
      var specularLight = getSpecularColor(pos, normal, LightSource, EyePos, n, k);

      var viewDir = (EyePos - pos).Normal;
      var cos1 = viewDir.Dot(normal);
      var cos2 = (1 - (1 - cos1.Square()) * refractiveIndex * refractiveIndex).Sqrt();
      var bias = (-refractiveIndex * viewDir - (cos2 - refractiveIndex * cos1) * normal) * (Thickness / 100);

      var uv1 = (LeftTop - LeftTop_Background + uv * Size) / Size_Background;
      return ColorBl.FromScRGB(1.0, (GlassColor.ScRGB * specularLight)
                                    + BackgroundMap[uv1 + new PointBl(bias.X, bias.Y)].ScRGB * Transparency + GlassColor.ScRGB * (1.0 - Transparency));
    }

    /// <summary>
    /// draw a CD with the diffraction effect,
    /// assumed that all the normal of the surface is (0, 0.5, 0.866), 
    /// and the tangent vector tangent to the line between the point and the center of CD
    /// </summary>
    /// <param name="uv">coordinate of point</param>
    /// <param name="input">input image</param>
    /// <param name="rainbowTex">
    /// the 1D texture to determine the color corresponding to the given wavelength, 
    /// we use a simple approximation of a rainbow map. Basically, the map should range 
    /// from violet to red and produce most colors in the rainbow
    /// </param>
    /// <param name="LightSource">information of the light source</param>
    /// <param name="EyePos">position of eye/viewport</param>
    /// <param name="LeftTop">LeftTop of the object to draw</param>
    /// <param name="Size">size of the object to draw</param>
    /// <returns>the final color after lighting calculation</returns>
    public static ColorBl DiffractionCD(PointBl uv, BrushBl input, BrushBl rainbowTex, PointLightBl LightSource, Point3DBl EyePos, PointBl LeftTop, PointBl Size) {
      var lightPosition = new Point3DBl(LightSource.Position.XY - LeftTop, LightSource.Position.Z);
      var eyePosition = EyePos - LeftTop;
      var P = new Point3DBl(uv * Size, 0.0);
      var L = (lightPosition - P).Normal;
      var V = (eyePosition - P).Normal;
      var H = L + V;
      var N = new Point3DBl(0, 0.5, 0.866);//(0,0.0,1);//
      var T = N.Cross(P - Size * 0.5);
      T /= T.Length;
      var u = T.Dot(H) * 10d;
      var e = 25 * u / N.Dot(H);
      var c = Math.E.Bl().Pow(-e.Square());
      u = (u < 0).Condition(-u, u);
      var cdiff = new Point3DBl(0, 0, 0);
      for (int n = 1; n < 8; n++) {
        cdiff += rainbowTex[new PointBl(2 * u / n - 1, 0.1)].ScRGB;
      }
      return ColorBl.FromScRGB(input[uv].ScA, ((new Point3DBl(c, c, c) + cdiff) * input[uv].ScRGB));
    }
    public static ColorBl DiffractionCD(PointBl uv, BrushBl input, PointLightBl LightSource, Point3DBl EyePos, PointBl LeftTop, PointBl Size) {
      return DiffractionCD(uv, input, Bling.ShaderLib.RainbowImage, LightSource, EyePos, LeftTop, Size);
    }

    public static ColorBl DiffractionCD(PointBl uv, BrushBl input, BrushBl rainbowTex, SpotLightBl LightSource, Point3DBl EyePos, PointBl LeftTop, PointBl Size) {
      var lightPosition = new Point3DBl(LightSource.Position.XY - LeftTop, LightSource.Position.Z);
      var eyePosition = EyePos - LeftTop;
      var P = new Point3DBl(uv * Size, 0.0);
      var L = (lightPosition - P).Normal;
      var V = (eyePosition - P).Normal;
      var H = L + V;
      var N = new Point3DBl(0, 0.5, 0.866);//(0,0.0,1);//
      var T = N.Cross(P - Size * 0.5);
      T /= T.Length;
      var u = T.Dot(H) * 10d;
      var e = 25 * u / N.Dot(H);
      var c = Math.E.Bl().Pow(-e.Square());
      u = (u < 0).Condition(-u, u);
      var cdiff = new Point3DBl(0, 0, 0);
      for (int n = 1; n < 8; n++) {
        cdiff += rainbowTex[new PointBl(2 * u / n - 1, 0.1)].ScRGB;
      }
      return ColorBl.FromScRGB(input[uv].ScA, ((new Point3DBl(c, c, c) + cdiff) * input[uv].ScRGB));
    }  
    
    /// <summary>
    /// draw a CD with the diffraction effect,
    /// assumed that all the normal of the surface is (0, 0.5, 0.866), 
    /// and the tangent vector tangent to the line between the point and the center of CD
    /// </summary>
    /// <param name="uv">coordinate of point</param>
    /// <param name="input">input image</param>
    /// <param name="rainbowTex">
    /// the 1D texture to determine the color corresponding to the given wavelength, 
    /// we use a simple approximation of a rainbow map. Basically, the map should range 
    /// from violet to red and produce most colors in the rainbow
    /// </param>
    /// <param name="LightSource">information of the light source</param>
    /// <param name="EyePos">position of eye/viewport</param>
    /// <param name="LeftTop">LeftTop of the object to draw</param>
    /// <param name="Size">size of the object to draw</param>
    /// <returns>the final color after lighting calculation</returns>
    public static ColorBl DiffractionCD(PointBl uv, BrushBl input, BrushBl rainbowTex, DirectionalLightBl LightSource, Point3DBl EyePos, PointBl LeftTop, PointBl Size) {
      var eyePosition = EyePos - LeftTop;
      var P = new Point3DBl(uv * Size, 0.0);
      var L = LightSource.Direction.Normal;
      var V = (eyePosition - P).Normal;
      var H = L + V;
      var N = new Point3DBl(0, 0.5, 0.866);//(0,0.0,1);//
      var T = N.Cross(P - Size * 0.5);
      T /= T.Length;
      var u = T.Dot(H) * 10d;
      var e = 25 * u / N.Dot(H);
      var c = Math.E.Bl().Pow(-e.Square());
      u = (u < 0).Condition(-u, u);
      var cdiff = new Point3DBl(0, 0, 0);
      for (int n = 1; n < 8; n++) {
        cdiff += rainbowTex[new PointBl(2 * u / n - 1, 0.1)].ScRGB;
      }
      return ColorBl.FromScRGB(input[uv].ScA, ((new Point3DBl(c, c, c) + cdiff) * input[uv].ScRGB));
    }
  }
  /*
  //shader class
  public class LightShader {
    /// <summary>
    /// transform the color value in normamap(rgb:0~1) to the value of a normal in the 3d space(xyz:-1~1)
    /// </summary>
    /// <param name="tex"></param>
    /// <returns></returns>
    protected static Point3DBl getNormal(Point3DBl tex) {
      return tex * 2 - new Point3DBl(1, 1, 1);
    }

    /// <summary>
    /// calculate the attenuation
    /// </summary>
    /// <param name="LightSource.Attenuation"></param>
    /// <param name="dis"></param>
    /// <returns></returns>
    protected static DoubleBl Attenuation(PointLightBl.AttenuationSet attenuationCoefficient, DoubleBl dis) {
      return 1d / (attenuationCoefficient.Quadratic * dis * dis + attenuationCoefficient.Linear * dis + attenuationCoefficient.Constant);
    } 
  };

  public class DiffusePaperLightShader : LightShader {
    public ColorBl DiffuseColor = Colors.CornflowerBlue;
    public PointLightBl LightSource;
    public PointBl LeftTop;
    public PointBl Size;
    public Func<BrushBl, PointBl, ColorBl> Shader {
      get {
        return (input, uv) => {
          var lightPosition = LightSource.Position.XY - LeftTop;
          var dir = new Point3DBl(lightPosition - uv * Size, (LightSource.Position.Z));
          var dis = dir.Length;
          dir = dir.Normal;
          var dot = dir.Z;

          return ColorBl.FromScRGB(1.0, DiffuseColor.ScRGB * LightSource.Color.ScRGB * dot * Attenuation(LightSource.Attenuation, dis));
        };
      }
    }
  }

  public class DiffuseLightShader : LightShader  {
    public ColorBl DiffuseColor;
    public BrushBl DiffuseMap;
    public BrushBl NormalMap;
    public BrushBl HeightMap;
    public DoubleBl HeightScale;
    public PointLightBl LightSource;
    public Point3DBl EyePos;
    public PointBl LeftTop;
    public PointBl Size;
    public Func<BrushBl, PointBl, ColorBl> Shader_withHeightMap {
      get {
        return (input, uv) => {
          var lightPosition = LightSource.Position.XY - LeftTop;
          var dir = new Point3DBl(lightPosition - uv * Size, LightSource.Position.Z - HeightMap[uv].ScR * HeightScale);
          var dis = dir.Length;
          dir = dir.Normal;

          var normal = NormalMap[uv].ScRGB * 2 - new Point3DBl(1, 1, 1);
          var dot = dir.Dot(normal);

          return ColorBl.FromScRGB(1.0, (DiffuseMap[uv].ScRGB * LightSource.Color.ScRGB * dot * Attenuation(LightSource.Attenuation, dis)));
        };
      }
    }

    public Func<BrushBl, PointBl, ColorBl> Shader {
      get {
        return (input, uv) => {
          var lightPosition = LightSource.Position.XY - LeftTop;
          var dir = new Point3DBl(lightPosition - uv * Size, (LightSource.Position.Z));
          var dis = dir.Length;
          dir = dir.Normal;

          var normal = NormalMap[uv].ScRGB * 2 - new Point3DBl(1, 1, 1);
          var dot = dir.Dot(normal);

          return ColorBl.FromScRGB(1.0, (DiffuseMap[uv].ScRGB * LightSource.Color.ScRGB * dot * Attenuation(LightSource.Attenuation, dis)));
        };
      }
    }  
  }

  public class DiffuseSpecularLightShader : LightShader {
    public BrushBl BaseMap;
    public BrushBl NormalMap;
    public PointLightBl LightSource;
    public Point3DBl EyePos;
    public PointBl LeftTop;
    public PointBl Size;
    public DoubleBl n;
    public DoubleBl k;
    public Func<BrushBl, PointBl, ColorBl> Shader {
      get {
        return (input, uv) => {
          var lightPosition = LightSource.Position.XY - LeftTop;
          var dir = new Point3DBl(lightPosition - uv * Size, (LightSource.Position.Z));
          var dis = dir.Length;
          dir = dir.Normal;

          var normal = NormalMap[uv].ScRGB * 2 - new Point3DBl(1, 1, 1);
          var dot = dir.Dot(normal);

          var eyePos0 = EyePos - LeftTop;
          var r = -dir + 2 * (dir.Dot(normal)) * normal;
          var viewDir = (eyePos0 - uv * Size).Normal;

          return ColorBl.FromScRGB(1.0, (BaseMap[uv].ScRGB * LightSource.Color.ScRGB * (dot * Attenuation(LightSource.Attenuation, dis) + r.Dot(viewDir).Pow(n) * k)));
        };
      }
    }
  }*/
}